package org.lld.im.service.group.service;

import com.lld.im.codec.pack.message.ChatMessageAck;
import org.lld.im.common.ResponseVO;
import org.lld.im.common.constant.Constants;
import org.lld.im.common.enums.command.GroupEventCommand;
import org.lld.im.common.enums.command.MessageCommand;
import org.lld.im.common.model.ClientInfo;
import org.lld.im.common.model.message.GroupChatMessageContent;
import org.lld.im.common.model.message.MessageContent;
import org.lld.im.common.model.message.OfflineMessageContent;
import org.lld.im.service.group.model.req.SendGroupMessageReq;
import org.lld.im.service.message.model.resp.SendMessageResp;
import org.lld.im.service.message.service.CheckSendMessageService;
import org.lld.im.service.message.service.MessageStoreService;
import org.lld.im.service.message.service.P2PMessageService;
import org.lld.im.service.seq.RedisSeq;
import org.lld.im.service.utils.MessageProducer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author: LunBoWang
 * @description: 群组消息服务
 * @date: 2025/4/4 下午12:16
 * @version: 1.0
 */
@Service
public class GroupMessageService {
    private static Logger logger = LoggerFactory.getLogger(P2PMessageService.class);

    @Resource
    CheckSendMessageService checkSendMessageService;

    @Resource
    MessageProducer messageProducer;

    @Resource
    ImGroupMemberService imGroupMemberService;

    @Resource
    MessageStoreService messageStoreService;

    @Resource
    RedisSeq redisSeq;

    private final ThreadPoolExecutor threadPoolExecutor;

    {
        AtomicInteger num = new AtomicInteger(0);
        threadPoolExecutor = new ThreadPoolExecutor(8, 8, 60, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(1000), new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setName("message-group-thread-" + num.getAndIncrement());
                thread.setDaemon(true);
                return thread;
            }
        });
    }

    public void process(GroupChatMessageContent messageContent) {
        String fromId = messageContent.getFromId();
        String groupId = messageContent.getGroupId();
        Integer appId = messageContent.getAppId();
        // 前置校验
        //这个用户是否被禁言 是否被禁用
        //发送方和接收方是否是好友关系
        MessageContent messageFromMessageIdCache = messageStoreService.getMessageFromMessageIdCache(messageContent.getAppId(), messageContent.getMessageId(),
                MessageContent.class);
        if (messageFromMessageIdCache != null) {
            threadPoolExecutor.execute(() -> {
                //1.回ack成功给自己
                ack(messageContent, ResponseVO.successResponse());
                //2.发消息给同步在线端
                syncToSender(messageContent, messageContent);
                //3.发消息给对方在线端
                dispatchMessage(messageContent);
            });
        }

        long seq = redisSeq.doGetSeq(messageContent.getAppId() + ":" + Constants.SeqConstants.GroupMessage
                + ":" + messageContent.getGroupId());
        messageContent.setMessageSequence(seq);
        threadPoolExecutor.execute(() -> {
            messageStoreService.storeGroupMessage(messageContent);

            List<String> groupMemberId = imGroupMemberService.getGroupMemberId(messageContent.getGroupId(), messageContent.getAppId());
            messageContent.setMemberId(groupMemberId);

            OfflineMessageContent offlineMessageContent = new OfflineMessageContent();
            BeanUtils.copyProperties(messageContent, offlineMessageContent);
            offlineMessageContent.setToId(messageContent.getGroupId());
            messageStoreService.storeGroupOfflineMessage(offlineMessageContent, groupMemberId);

            //1.回ack成功给自己
            ack(messageContent, ResponseVO.successResponse());
            //2.发消息给同步在线端
            syncToSender(messageContent, messageContent);
            //3.发消息给对方在线端
            dispatchMessage(messageContent);

            messageStoreService.setMessageFromMessageIdCache(messageContent.getAppId(),
                    messageContent.getMessageId(), messageContent);
        });
    }

    private void dispatchMessage(GroupChatMessageContent messageContent) {
        for (String memberId : messageContent.getMemberId()) {
            if (!memberId.equals(messageContent.getFromId())) {
                messageProducer.sendToUser(memberId, GroupEventCommand.MSG_GROUP,
                        messageContent, messageContent.getAppId());
            }
        }
    }

    private void ack(MessageContent messageContent, ResponseVO responseVO) {
        logger.info("msg ack,msgId={},checkResult={}", messageContent.getMessageId(), responseVO.getCode());

        ChatMessageAck chatMessageAck = new ChatMessageAck(messageContent.getMessageId());
        responseVO.setData(chatMessageAck);
        //发消息
        messageProducer.sendToUser(messageContent.getFromId(), GroupEventCommand.GROUP_MSG_ACK,
                responseVO, messageContent);
    }

    private void syncToSender(GroupChatMessageContent messageContent, ClientInfo clientInfo) {
        messageProducer.sendToUserExceptClient(messageContent.getFromId(),
                GroupEventCommand.MSG_GROUP, messageContent, messageContent);
    }

    public ResponseVO imServerPermissionCheck(String fromId, String groupId, Integer appId) {
        ResponseVO responseVO = checkSendMessageService.
                checkGroupMessage(fromId, groupId, appId);
        return responseVO;
    }

    public SendMessageResp send(SendGroupMessageReq req) {
        SendMessageResp sendMessageResp = new SendMessageResp();
        GroupChatMessageContent message = new GroupChatMessageContent();
        BeanUtils.copyProperties(req, message);

        messageStoreService.storeGroupMessage(message);

        sendMessageResp.setMessageKey(message.getMessageKey());
        sendMessageResp.setMessageTime(System.currentTimeMillis());

        //发消息给同步在线端
        syncToSender(message, message);
        //发消息给对方在线端
        dispatchMessage(message);

        return sendMessageResp;
    }
}
